#!/bin/bash
determine_new_version() {
	grep "version = " "$1" | sed -Ee 's/version = "(.*)"/\1/' | head -1
}

check_notexists_version() {
	cirrus_agent="${CIRRUS_CI/?*/(Cirrus-CI)}"
	final_agent="Release-Script/1.0 ${cirrus_agent:-(local)} (for static-alloc) (author:HeroicKatora)"
	echo $final_agent
	# Does the api information start with: '{"errors":'
	[[ $(wget -U "%final_agent" "https://crates.io/api/v1/crates/oxide-auth/$new_version" -qO -) == "{\"errors\":"* ]]
}

git_considered_clean() {
	[[ -z $(git status -s) ]]
}

count_wip_marker() {
	# WIP alone is not a marker
	[[ -z $(grep "\[WIP\]" Migration.md Readme.md) ]]
}

check_release_changes() {
	[[ -z $(grep "# v$new_version" Changes.md) ]]
}

check_target_features() {
	if [[ -z $CIRRUS_CI ]]; then
		cargo test -p oxide-auth-actix &&
		cargo +nightly test -p oxide-auth-rocket &&
		cargo test -p oxide-auth-iron &&
		cargo test -p oxide-auth-rouille
	else
		echo "Executing on CI, skipping feature checks"
	fi
}

check_packaging() {
	pushd $1 && cargo package && popd
}

make_git_tag() {
	# Extract the verion specific section from Changes.md
	#   Delete lines until $new_version header
	#   Delete lines starting from the next header
	#   Delete all empty lines at the start
	# Use as the initial message for a signed tag, but open edit anyways
	sed -e '1,/'"$new_version"'/d;/\#/,$d;/./,$!d' Changes.md | git tag -s $is_force -F - -e "v$new_version"
}

is_force=""
do_tag=""
do_version_check="yes"

for param in $@
do
	case "$param" in
		-f) is_force="-f";;
		--no-version-check) do_version_check="";;
		--tag) do_tag="yes";;
		--help) ;&
		-h) { cat << EOF
usage: release [-f] [-h|--help] <version>

Automates checks and tagging of new releases. Encourages a workflow where
planned changes are integrated into readme and migration documentation early,
with WIP markers to help produce complete logs.

  -f		Force usage of version, even if such a tag already exists.
  -h, --help    Display this help
  <version>	A semantic version number matching [0-9a-zA-Z.-]*
  
EOF
exit 1; } ;;
	esac
done

# Check that the working dir is clean. May comment this out if it produces problems.
git_considered_clean || { echo "Fail: Working directory is not clean"; exit 1; }

# Check that for every author, we have at least name or mail recorded in Contributors.txt
# For each commit author, checks that either his/her name or respective mail
# address appears in the contributors file. Note that a .mailcap file could be
# introduced to canonicalize these names in the output of git-shortlog already.
# Since this needs GNU parallel, the check is optional.
if which parallel 2>/dev/null; then
	{ (git shortlog -se | parallel -C '\t|<' grep -Fq -e '{2}' -e '\<{3}' Contributors.txt) || { echo "Fail: contributor not listed"; exit 1; }; }
else
	{ echo "Checking contributors needs GNU parallel, please make sure manually." 1>&2; }
fi

new_version="$(determine_new_version "oxide-auth/Cargo.toml")"

# check it is a sane version number
[[ -z $(grep -vE '[0-9a-zA-Z.-]*' <<< "$new_version" ) ]] || { echo "Fail: Check version number: ${new_version}"; exit 1; }

[[ -z $version_check ]] || check_notexists_version || { echo "Version $new_version appears already published"; exit 1; }

# Check there are no more [WIP] markers in Migrate and Readme
count_wip_marker || { echo "Fail: Work in progress in documentation"; exit 1; }

# Find a matching header in the changelog
check_release_changes && { echo "Fail: No changelog regarding this release"; exit 1; }

# Packaging works. Note: does not publish the version.
check_packaging oxide-auth || { echo "Fail: cargo could not package successfully"; exit 1; }

check_target_features || { echo "Fail: one or more required target-feature combinations doesnt compile its example properly"; exit 1; }

[[ -z $do_tag ]] || make_git_tag
